<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE连接诊断工具</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            padding: 20px;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
            padding: 30px;
        }
        
        h1 {
            color: #2c3e50;
            margin-bottom: 20px;
            text-align: center;
        }
        
        .status-indicator {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 15px;
            background-color: #f0f0f0;
            border-radius: 8px;
            margin-bottom: 25px;
        }
        
        .status-dot {
            width: 15px;
            height: 15px;
            border-radius: 50%;
            background-color: #e74c3c;
        }
        
        .status-dot.connected {
            background-color: #2ecc71;
            box-shadow: 0 0 10px rgba(46, 204, 113, 0.5);
        }
        
        .status-dot.connecting {
            background-color: #f39c12;
            animation: pulse 1.5s infinite;
        }
        
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }
        
        .form-group {
            margin-bottom: 25px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #2c3e50;
        }
        
        input[type="text"] {
            width: 100%;
            padding: 12px 15px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 1rem;
            transition: border-color 0.3s;
        }
        
        input[type="text"]:focus {
            border-color: #3498db;
            outline: none;
            box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
        }
        
        button {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 12px 25px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 1.1rem;
            font-weight: 500;
            transition: background-color 0.2s;
            display: block;
            width: 100%;
            margin-top: 10px;
        }
        
        button:hover {
            background-color: #2980b9;
        }
        
        .results {
            margin-top: 30px;
            display: none;
        }
        
        .panel {
            background-color: #f9f9f9;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
        }
        
        .panel-title {
            font-size: 1.2rem;
            color: #2c3e50;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }
        
        .event-log {
            height: 300px;
            overflow-y: auto;
            padding: 15px;
            background-color: #2c3e50;
            color: #ecf0f1;
            border-radius: 6px;
            font-family: 'Courier New', monospace;
            white-space: pre-wrap;
            line-height: 1.5;
        }
        
        .error-panel {
            background-color: #ffebee;
            color: #c62828;
            padding: 15px;
            border-radius: 6px;
            margin-top: 20px;
            display: none;
        }
        
        .diagnosis {
            background-color: #e3f2fd;
            padding: 15px;
            border-radius: 6px;
            margin-top: 20px;
        }
        
        .diagnosis h3 {
            color: #1976d2;
            margin-bottom: 10px;
        }
        
        .solution-list {
            padding-left: 20px;
        }
        
        .solution-list li {
            margin-bottom: 8px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>SSE连接诊断工具</h1>
        
        <div class="status-indicator">
            <div class="status-dot" id="status-dot"></div>
            <span id="status-text">准备测试连接</span>
        </div>
        
        <div class="form-group">
            <label for="sse-url">SSE端点URL:</label>
            <input type="text" id="sse-url" value="http://localhost:8000/api/chat_stream?user_input=你好">
        </div>
        
        <button id="test-button">测试SSE连接</button>
        
        <div class="results" id="results">
            <div class="panel">
                <h2 class="panel-title">事件日志</h2>
                <div class="event-log" id="event-log"></div>
            </div>
            
            <div class="error-panel" id="error-panel">
                <h2 class="panel-title">错误详情</h2>
                <div id="error-message"></div>
            </div>
            
            <div class="diagnosis">
                <h3>问题诊断</h3>
                <p id="diagnosis-text">等待测试结果...</p>
                
                <h3>建议解决方案</h3>
                <ul class="solution-list" id="solution-list">
                    <li>等待测试结果...</li>
                </ul>
            </div>
        </div>
    </div>

    <script>
        // DOM元素引用
        const sseUrlInput = document.getElementById('sse-url');
        const testButton = document.getElementById('test-button');
        const statusDot = document.getElementById('status-dot');
        const statusText = document.getElementById('status-text');
        const eventLog = document.getElementById('event-log');
        const errorPanel = document.getElementById('error-panel');
        const errorMessage = document.getElementById('error-message');
        const results = document.getElementById('results');
        const diagnosisText = document.getElementById('diagnosis-text');
        const solutionList = document.getElementById('solution-list');
        
        let eventSource = null;
        
        // 更新状态指示器
        function updateStatus(text, color, className = '') {
            statusText.textContent = text;
            statusDot.style.backgroundColor = color;
            statusDot.className = 'status-dot ' + className;
        }
        
        // 添加日志
        function addLog(message, type = 'info') {
            const timestamp = new Date().toLocaleTimeString();
            const logEntry = document.createElement('div');
            
            logEntry.textContent = `[${timestamp}] ${message}`;
            
            if (type === 'error') {
                logEntry.style.color = '#ff6b6b';
            } else if (type === 'success') {
                logEntry.style.color = '#2ecc71';
            } else if (type === 'warning') {
                logEntry.style.color = '#f39c12';
            }
            
            eventLog.appendChild(logEntry);
            eventLog.scrollTop = eventLog.scrollHeight;
        }
        
        // 显示错误
        function showError(message) {
            errorMessage.textContent = message;
            errorPanel.style.display = 'block';
        }
        
        // 隐藏错误
        function hideError() {
            errorPanel.style.display = 'none';
        }
        
        // 更新诊断结果
        function updateDiagnosis(diagnosis, solutions) {
            diagnosisText.textContent = diagnosis;
            
            // 清空解决方案列表
            while (solutionList.firstChild) {
                solutionList.removeChild(solutionList.firstChild);
            }
            
            // 添加新的解决方案
            solutions.forEach(solution => {
                const li = document.createElement('li');
                li.textContent = solution;
                solutionList.appendChild(li);
            });
        }
        
        // 测试SSE连接
        function testSSEConnection() {
            // 重置状态
            eventLog.innerHTML = '';
            hideError();
            updateStatus('正在连接...', '#f39c12', 'connecting');
            results.style.display = 'block';
            
            // 关闭现有连接
            if (eventSource) {
                eventSource.close();
                eventSource = null;
            }
            
            // 获取URL
            const url = sseUrlInput.value;
            addLog(`开始测试SSE连接: ${url}`);
            addLog('创建EventSource实例...');
            
            try {
                // 创建新的SSE连接
                eventSource = new EventSource(url);
                
                // 连接打开事件
                eventSource.onopen = () => {
                    addLog('连接已建立', 'success');
                    updateStatus('已连接', '#2ecc71', 'connected');
                };
                
                // 消息事件
                eventSource.onmessage = (event) => {
                    addLog(`收到消息事件: ${event.data}`, 'info');
                };
                
                // 自定义事件监听器
                eventSource.addEventListener('status', (event) => {
                    addLog(`收到状态事件: ${event.data}`, 'info');
                });
                
                eventSource.addEventListener('message', (event) => {
                    addLog(`收到消息事件: ${event.data}`, 'info');
                });
                
                eventSource.addEventListener('complete', (event) => {
                    addLog(`收到完成事件: ${event.data}`, 'success');
                    updateStatus('测试完成', '#2ecc71', 'connected');
                    
                    // 诊断结果
                    updateDiagnosis("连接成功建立并完成数据传输", [
                        "检查前端事件处理逻辑是否正确",
                        "确保后端正确关闭SSE连接",
                        "验证事件数据格式是否符合规范"
                    ]);
                });
                
                eventSource.addEventListener('error', (event) => {
                    addLog(`收到错误事件: ${event.data}`, 'error');
                    showError(`错误事件: ${event.data}`);
                    updateStatus('连接错误', '#e74c3c');
                    
                    // 诊断结果
                    updateDiagnosis("后端发送了错误事件", [
                        "检查后端错误处理逻辑",
                        "验证错误事件数据格式",
                        "确保后端不会发送未定义的事件数据"
                    ]);
                });
                
                // 错误事件
                eventSource.onerror = (error) => {
                    addLog(`连接错误: ${error.type}`, 'error');
                    showError(`连接错误: ${error.type}`);
                    updateStatus('连接中断', '#e74c3c');
                    
                    // 诊断结果
                    updateDiagnosis("SSE连接发生错误", [
                        "检查网络连接是否稳定",
                        "验证后端服务是否正常运行",
                        "检查CORS配置是否正确",
                        "确保SSE端点URL正确无误"
                    ]);
                };
            } catch (error) {
                addLog(`创建EventSource失败: ${error.message}`, 'error');
                showError(`创建EventSource失败: ${error.message}`);
                updateStatus('连接失败', '#e74c3c');
                
                // 诊断结果
                updateDiagnosis("无法创建EventSource实例", [
                    "检查URL格式是否正确",
                    "确保协议为http或https",
                    "验证浏览器是否支持EventSource",
                    "尝试使用不同的浏览器测试"
                ]);
            }
        }
        
        // 事件监听器
        testButton.addEventListener('click', testSSEConnection);
    </script>
</body>
</html>
